﻿using UnityEngine.UIElements;

namespace winS.UnityEditor.UIElement
{
    /// <summary>
    /// 一个可折叠的标签.
    /// 默认处于打开状态
    /// </summary>
    public class Foldout : UndoableValueControl<bool>, IHasLabel
    {
        public static readonly float defaultIndent = 18f;
        public static readonly float defaultIconSize = 12f;
        public static readonly float defaultAnimationDuration = 0.24f;

        public float indent { get => _indent; set => content.style.marginLeft = _indent = value; }
        public float animationDuration { get => _animationDuration; set => SetAnimationDuration(value); }

        public Row head { get; private set; }
        public Label label { get; private set; }
        public override VisualElement contentContainer => content;

        private float _indent = defaultIndent;
        private float _animationDuration = defaultAnimationDuration;

        private readonly Icon icon;
        private readonly VisualElement content;
        private readonly VisualElement contentParent;

        internal Foldout(ElementFactory elementFactory) : base(elementFactory)
        {
            style.SetVerticalMargin(0f);

            hierarchy.Add(head = EditorElementUtility.elementFactory.CreateRow());
            head.style.overflow = Overflow.Hidden;
            head.style.minHeight = EditorElementUtility.fieldMinHeight;
            head.RegisterCallback<ClickEvent>(ClickCallback);
            head.RegisterCallback<MouseDownEvent>(MouseDownCallback);

            head.Add(icon = EditorElementUtility.elementFactory.CreateIcon(PackageAssets.Icons.arrowDown, defaultIconSize, ColorLevelUtility.GetColor(12)));
            icon.pickingMode = PickingMode.Ignore;
            icon.style.SetTransition("rotate", animationDuration);

            head.Add(label = EditorElementUtility.elementFactory.CreateLabel());
            label.pickingMode = PickingMode.Ignore;
            label.style.marginLeft = 6f;

            hierarchy.Add(contentParent = EditorElementUtility.elementFactory.CreateEditorElementWithName("内容父级"));
            contentParent.style.marginLeft = indent;
            contentParent.style.overflow = Overflow.Hidden;
            contentParent.style.SetTransition("height", animationDuration);

            contentParent.Add(content = EditorElementUtility.elementFactory.CreateEditorElementWithName("折叠内容"));
            content.style.position = Position.Absolute;
            content.style.SetMinWidth(100f, LengthUnit.Percent);
            content.RegisterCallback<GeometryChangedEvent>(ContentGeometryChangedCallback);

            base.SetValueWithoutNotify(true);//默认展开
        }

        public override void SetValueWithoutNotify(bool value)
        {
            if (this.value == value) return;
            base.SetValueWithoutNotify(value);
            CheckFoldState();
        }

        protected override void SetValue(bool value)
        {
            if (this.value == value) return;
            base.SetValue(value);
            CheckFoldState();
        }

        private void CheckFoldState()
        {
            if (value)
            {
                contentParent.style.height = content.layout.height;
                icon.style.SetRotate(0f);
            }
            else
            {
                contentParent.style.height = 0f;
                icon.style.SetRotate(-90f);
            }
        }
        private void SetAnimationDuration(float newAnimationDuration)
        {
            _animationDuration = newAnimationDuration;
            contentParent.style.SetTransition("height", animationDuration);
        }
        private void ClickCallback(ClickEvent clickEvent)
        {
            SetValue(!value);
        }
        private void MouseDownCallback(MouseDownEvent mouseDownEvent)
        {
            mouseDownEvent.StopPropagation();
        }
        private void ContentGeometryChangedCallback(GeometryChangedEvent geometryChangedEvent)
        {
            if (!value) return;
            //内容改变时, 不要播放动画.
            //如果内容里也恰巧包含Foldout, 由于各自的内容不同, 各自的动画时长也不相同, 会导致里面的动画播完后当前Foldout还在播放动画, 会有错误感
            contentParent.style.transitionProperty = EditorElementUtility.emptyPropertyList;
            contentParent.style.height = geometryChangedEvent.newRect.height;
            contentParent.style.transitionProperty = EditorElementUtility.heightPropertyList;
        }
    }
}